package com.dragon.logical.service.avttendance.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dragon.common.constant.CronJobConstant;
import com.dragon.common.model.ResultCode;
import com.dragon.common.model.exception.CustomException;
import com.dragon.common.util.CronzUtil;
import com.dragon.common.util.JwtUtil;
import com.dragon.common.util.StringUtils;
import com.dragon.logical.service.auth.TasksService;
import com.dragon.logical.service.avttendance.IScheduleService;
import com.dragon.repository.entity.*;
import com.dragon.repository.mapper.AdminMapper;
import com.dragon.repository.mapper.ScheduleMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 日程表 服务实现类
 * </p>
 *
 * @author sy
 * @since 2023-07-10
 */
@Service
public class ScheduleServiceImpl extends ServiceImpl<ScheduleMapper, Schedule> implements IScheduleService {

    @Autowired
    ScheduleMapper scheduleMapper;

    @Autowired
    TasksService tasksService;
    @Autowired
    AdminMapper adminMapper;

    @Override
    public Map<String, List<Schedule>> getList(Integer adminId, String time) {
        QueryWrapper<Schedule> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotEmpty(time)) {

        }
        wrapper.lambda()
                .eq(adminId !=null,Schedule::getCreateAdminId,adminId)
                .apply(StrUtil.isNotBlank(time)," date_format(start_time,'%y%mm%') = date_format('" + time + "-01','%y%mm%')");
//        wrapper.lambda().eq(Schedule::getCreateAdminId,adminId);
        List<Schedule> schedules = scheduleMapper.selectList(wrapper);
        schedules.stream().forEach(s ->  s.setJudgmentTime(DateUtil.format(s.getStartTime(),"yyyy-MM-dd")));
        Map<String, List<Schedule>> collect = schedules
                .stream()
                .collect(Collectors.groupingBy(Schedule::getJudgmentTime));
        return collect;
    }

    @Override
    public Page<Schedule> scheduleNotExpired(Integer page, Integer limit, Integer adminId){
        Page<Schedule> schedulePage = new Page<>(page, limit);
        QueryWrapper<Schedule> wrapper = new QueryWrapper<>();
        wrapper.eq("M.create_admin_id", adminId)
                .apply("LEFT(M.end_time,10) >= LEFT(NOW(),10)")
                .orderByDesc("M.create_time");
        Page<Schedule> schedulePage1 = scheduleMapper.selectScheduleNotExpiredPage(schedulePage, wrapper);
        return schedulePage1;
    }

    @Override
    public Page<Schedule> listBySearch(Integer page, Integer limit, String time , String search, HttpServletRequest request){
        Integer adminId = Integer.valueOf(JwtUtil.getAdminId(request));
        List<Schedule> schedules = scheduleMapper.selectMyPage(adminId, time, search);
        return listToPage(schedules,limit,page);
    }

    @Override
    public void addSchedule(Schedule schedule){
        schedule.setCreateTime(DateUtil.date());
        if (schedule.getEventType() == 0) {
            scheduleMapper.insert(schedule);
        } else {
            Boolean time = null ;
            switch (schedule.getRemindType()){
                case 1:
                    time = DateUtil.offsetMinute(schedule.getStartTime(), -5).after(DateUtil.date());
                    break;
                case 2:
                    time = DateUtil.offsetMinute(schedule.getStartTime(), -15).after(DateUtil.date());
                    break;
                case 3:
                    time = DateUtil.offsetMinute(schedule.getStartTime(), -30).after(DateUtil.date());
                    break;
                case 4:
                    time = DateUtil.offsetHour(schedule.getStartTime(), -1).after(DateUtil.date());
                    break;
                case 5:
                    time = DateUtil.offsetHour(schedule.getStartTime(), -2).after(DateUtil.date());
                    break;
                case 6:
                    time = DateUtil.offsetDay(schedule.getStartTime(), -1).after(DateUtil.date());
                    break;
                case 7:
                    time = DateUtil.offsetDay(schedule.getStartTime(), -2).after(DateUtil.date());
                    break;
            }
            if (time == false){
                throw new CustomException(ResultCode.NOT_ENOUGH_TIME);
            }
            scheduleMapper.insert(schedule);
            sendTasks(schedule);
        }
    }

    @Override
    public void updateSchedule(Schedule schedule){
        tasksService.deleteTrigger(CronJobConstant.REMINDER_TRIGGER_NAME.variable().concat(String.valueOf(schedule.getId())),
                CronJobConstant.REMINDER_TRIGGER_GROUP.variable().concat(String.valueOf(schedule.getId())));
        scheduleMapper.updateById(schedule);
        sendTasks(schedule);
    }

    @Override
    public void deleteSchedule(Integer id){
        scheduleMapper.deleteById(id);
    }

    @Override
    public Schedule detailOne(Integer id) {
        Schedule schedule = scheduleMapper.selectDetail(id);
        //获取参与人名称
        if (StrUtil.isNotBlank(schedule.getOwnerAdminIds())){
            List<Integer> ownerAdminIds = Stream.of(schedule.getOwnerAdminIds().split(",")).map(Integer::valueOf).collect(Collectors.toList());
            List<Admin> adminList = adminMapper.selectBatchIds(ownerAdminIds);
            String ownerAdminName = adminList.stream().map(a -> a.getUsername()).collect(Collectors.joining(","));
            schedule.setOwnerAdminNames(ownerAdminName);
        }
        return schedule;
    }

    @Override
    public List<Schedule> getListForDay(Integer adminId, String time) {
        QueryWrapper<Schedule> wrapper = new QueryWrapper<>();
        wrapper.eq("M.create_admin_id", adminId)
                .apply("LEFT(M.start_time,10) = LEFT('"+time+"',10)");
        List<Schedule> schedules = scheduleMapper.selectListForDay(wrapper);
        schedules.forEach(schedule -> {
            //获取参与人名称
            if (StrUtil.isNotBlank(schedule.getOwnerAdminIds())){
                List<Integer> ownerAdminIds = Stream.of(schedule.getOwnerAdminIds().split(",")).map(Integer::valueOf).collect(Collectors.toList());
                List<Admin> adminList = adminMapper.selectBatchIds(ownerAdminIds);
                String ownerAdminName = adminList.stream().map(a -> a.getUsername()).collect(Collectors.joining(","));
                schedule.setOwnerAdminNames(ownerAdminName);
            }
        });
        return schedules;
    }

    private void sendTasks(Schedule schedule){
        if(schedule.getEventType()==0) {
            return;
        }
        HashMap<String,String> params = new HashMap<>();
        String adminIds = "";
        if(StrUtil.isNotBlank(schedule.getOwnerAdminIds())){
            adminIds = schedule.getOwnerAdminIds();
            adminIds.concat(",").concat(String.valueOf(schedule.getCreateAdminId()));
        } else {
            adminIds = String.valueOf(schedule.getCreateAdminId());
        }
        params.put("adminIds",adminIds);
        params.put("title",schedule.getTitle());
        params.put("correlationId",String.valueOf(schedule.getId()));
        String cronExpression = switchDate(schedule.getRemindType(),schedule.getStartTime());
        Tasks tasks = Tasks.builder()
                .cronExpression(cronExpression)
                .jobName(CronJobConstant.REMINDER_JOB_NAME.variable())
                .jobForName(CronJobConstant.REMINDER_JOB_CLASS_NAME.variable())
                .jobGroupName(CronJobConstant.REMINDER_JOB_GROUP.variable())
                .triggerName(CronJobConstant.REMINDER_TRIGGER_NAME.variable().concat(String.valueOf(schedule.getId())))
                .triggerGroup(CronJobConstant.REMINDER_TRIGGER_GROUP.variable().concat(String.valueOf(schedule.getId())))
                .params(JSONObject.toJSONString(params))
                .build();
        tasksService.addSchedule(tasks);
    }


    private String switchDate(Integer type,Date date){
        String cronExpression = "";
        //0准时提醒 1：5分钟前 2：15分钟前 3：30分钟前 4：一个小时前 5：两个小时前 6：一天前 7：两天前 8：一周前
        switch (type){
            case 0:
                cronExpression = CronzUtil.createCronExpression(date,0,7);
                break;
            case 1:
                cronExpression = CronzUtil.createCronExpression(DateUtil.offsetMinute(date,-5),0,7);
                break;
            case 2:
                cronExpression = CronzUtil.createCronExpression(DateUtil.offsetMinute(date,-15),0,7);
                break;
            case 3:
                cronExpression = CronzUtil.createCronExpression(DateUtil.offsetMinute(date,-30),0,7);
                break;
            case 4:
                cronExpression = CronzUtil.createCronExpression(DateUtil.offsetHour(date,-1),0,7);
                break;
            case 5:
                cronExpression = CronzUtil.createCronExpression(DateUtil.offsetHour(date,-2),0,7);
                break;
            case 6:
                cronExpression = CronzUtil.createCronExpression(DateUtil.offsetDay(date,-1),0,7);
                break;
            case 7:
                cronExpression = CronzUtil.createCronExpression(DateUtil.offsetDay(date,-2),0,7);
                break;
            case 8:
                cronExpression = CronzUtil.createCronExpression(DateUtil.offsetWeek(date,-1),0,7);
                break;
        }
        return cronExpression;
    }

    /* List 转 Page */
    private <T> Page<T> listToPage(List<T> dataList, Integer pageSize, Integer pageNumber){
        Page<T> result = new Page<T>();
        List<T> monitors = new ArrayList<T>();
        if(dataList!=null && dataList.size()>0){
            int currentIndex = pageNumber>1?(pageNumber-1)*pageSize:0;
            for(int i=0; i<pageSize &&i<dataList.size()-currentIndex;i++){
                T data = dataList.get(currentIndex +i);
                monitors.add(data);
            }
            result.setRecords(monitors);
            result.setTotal(dataList.size());
            result.setCurrent(pageNumber);
            result.setSize(pageSize);
        }
        return result;
    }
}
